#include "spl.includes.h"
#include "splib.h"

using namespace SPLib;
using namespace SPLib::Controls;

#define BUFFER_INCREMENT    50

ControlTheme gThemeGray = {
  0xFFBBBBBB,
  0xFF666666,
  0x33FFFFFF,
  0xFF555555,
  0x22000000,
  0x88FFFFFF,
  0x66000000,
  0xFFFFFFFF,
  0xFFFFFFFF,
  0xFFFFFFFF,
  0xFF444444,
  0xFF666666
};

ControlTheme gThemeBlue = {
  0xFFBBBBBB,
  0xFF33CCFF,
  0x33FFFFFF,
  0xFF25AFFF,
  0x22000000,
  0x88FFFFFF,
  0xFF00AADD,
  0xFFFFFFFF,
  0xFFFFFFFF,
  0xFFFFFFFF,
  0xFF444444,
  0xFF666666
};

ControlTheme gThemeOrange = {
  0xFFBBBBBB,
  0xFFFFBD00,
  0x33FFFFFF,
  0xFFFF9900,
  0x22000000,
  0x88FFFFFF,
  0xFFDDAA00,
  0xFFFFFFFF,
  0xFFFFFFFF,
  0xFFFFFFFF,
  0xFF444444,
  0xFF666666
};

ControlTheme gGlobalTheme = gThemeGray;

VOID    Control::setTheme(ThemeStyle value)
{
  switch (value)
  {
  case ThemeBlue:
    gGlobalTheme = gThemeBlue;
    break;
  case ThemeOrange:
    gGlobalTheme = gThemeOrange;
    break;
  default:
    gGlobalTheme = gThemeGray;
    break;
  }
}

VOID    Control::setTheme(const ControlTheme* value)
{
  gGlobalTheme = *value;
}

const ControlTheme& Control::getTheme()
{
  return gGlobalTheme;
}

VOID    Control::onEraseBackground(Event::EraseBackgroundEvent& iEvent)
{
  // cancel background erase (done in Control::onPaint)
  *iEvent.handled = TRUE;
}

VOID    Control::onSize(Event::SizeEvent& iEvent)
{
  // update painting buffer
  if (!iEvent.width || !iEvent.height)
  {
    // invalid size, destroy buffer
    delete buffer;
    buffer = NULL;
  }
  else if (buffer)
  {
    // new buffer size
    INT cxBuffer = buffer->GetWidth(), cyBuffer = buffer->GetWidth();

    // calculate new buffer width
    if (cxBuffer < iEvent.width)
      cxBuffer = iEvent.width + BUFFER_INCREMENT;
    else if (cxBuffer - BUFFER_INCREMENT * 2 > iEvent.width)
      cxBuffer = iEvent.width + BUFFER_INCREMENT;

    // calculate new buffer height
    if (cyBuffer < iEvent.height)
      cyBuffer = iEvent.height + BUFFER_INCREMENT;
    else if (cyBuffer - BUFFER_INCREMENT * 2 > iEvent.height)
      cyBuffer = iEvent.height + BUFFER_INCREMENT;

    // if new buffer size changed
    if (buffer->GetWidth() != cxBuffer || buffer->GetHeight() != cyBuffer)
    {
      // recreate painting buffer
      delete buffer;
      buffer = new Gdip::Bitmap(cxBuffer, cyBuffer);
    }
  }
  else
  {
    // create painting buffer
    buffer = new Gdip::Bitmap(
      iEvent.width + BUFFER_INCREMENT,
      iEvent.height + BUFFER_INCREMENT);
  }

  // redraw control
  invalidate(FALSE);
}

VOID    Control::onPaint()
{
  // gdi stuff
  PAINTSTRUCT ps;
  // window size
  Geom::Rect size = Geom::Rect::fromClient(*this);

  // initialize gdi
  beginPaint(&ps);

  {
    // setup buffer graphics
    Gdip::Graphics g(buffer);

    g.SetPixelOffsetMode(Gdip::PixelOffsetModeNone);
    g.SetSmoothingMode(Gdip::SmoothingModeAntiAlias);
    g.Clear(backColor);

    // paint control
    onControlPaint(ControlPaintEvent(
      g,
      Gdip::Rect(
      0,
      0,
      size.getWidth(),
      size.getHeight()
      ),
      *(Geom::Rect*)&ps.rcPaint));
    //graph->Flush(FlushIntentionSync);
  }

  {
    // setup window graphics
    Gdip::Graphics g(ps.hdc);
    g.SetCompositingQuality(Gdip::CompositingQualityHighSpeed);
    g.SetCompositingMode(Gdip::CompositingModeSourceCopy);

    // copy cache to screen
    g.SetClip(Gdip::Rect(
      ps.rcPaint.left,
      ps.rcPaint.top,
      ps.rcPaint.right - ps.rcPaint.left,
      ps.rcPaint.bottom - ps.rcPaint.top));

    g.DrawCachedBitmap(&Gdip::CachedBitmap(buffer, &g), 0, 0);
    //graph->Flush(FlushIntentionSync);
  }

  // stop painting
  endPaint(&ps);
}

VOID  Control::sendNotify(NMHDR& iValue)
{
  iValue.hwndFrom   = *this;
  iValue.idFrom     = getID();

  SendMessage(
    mNotifyWindow ? mNotifyWindow : getParent(),
    WM_NOTIFY,
    getID(),
    (LPARAM)&iValue);
}
